package com.xcity.game.activity2.circle;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.alibaba.fastjson.JSONObject;
import com.xcity.Server;
import com.xcity.db.entity.Activity;
import com.xcity.db.entity.Player;
import com.xcity.db.entity.Ranking;
import com.xcity.game.activity2.ActivityIds;
import com.xcity.game.activity2.ActivityImpl;
import com.xcity.game.common.Cause;
import com.xcity.game.common.MessageConst;
import com.xcity.game.common.PlayerPool;
import com.xcity.game.event.GameEvents;
import com.xcity.game.item.ItemTemplate;
import com.xcity.game.mail.MailAttach;
import com.xcity.game.mail.MailService;
import com.xcity.game.player.PlayerService;
import com.xcity.game.rank.RankingListEnum;
import com.xcity.game.vip.VipUtils;
import com.xcity.pomelo.PomeloRoute;
import com.xcity.pomelo.push.msg.ActivityStatePush;
import com.xcity.pomelo.request.ActivityCircleInfoRequest;
import com.xcity.pomelo.request.ActivityCircleRankListRequest;
import com.xcity.pomelo.request.ActivityCircleRollRequest;
import com.xcity.pomelo.request.ActivityCircleShopBuyRequest;
import com.xcity.pomelo.request.ActivityCircleShopListRequest;
import com.xcity.pomelo.response.ActivityCircleInfoResponse;
import com.xcity.pomelo.response.ActivityCircleRankListResponse;
import com.xcity.pomelo.response.ActivityCircleRollResponse;
import com.xcity.pomelo.response.ActivityCircleRollResponse.CircleRewardInfo;
import com.xcity.pomelo.response.ActivityCircleShopBuyResponse;
import com.xcity.pomelo.response.ActivityCircleShopListResponse;
import com.xcity.pomelo.response.HintResponse;
import com.xcity.util.RandomUtils;

import gnu.trove.map.hash.TIntObjectHashMap;
import naga.x.App;
import naga.x.event.Event;
import naga.x.event.EventListener;
import naga.x.game.template.TemplateService;
import naga.x.game.time.DayListener;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Session;
import naga.x.net.annotation.OPHandler;
import naga.x.net.impl.pomelo.annotation.PomeloOP;
import naga.x.service.ServiceException;
import naga.x.util.CommonUtils;
import naga.x.util.TimeUtils;

/**
 * 欢乐转盘
 * @author shipeng.zhu
 */
@OPHandler
public class CircleActivity extends ActivityImpl implements EventListener, DayListener {
	
	protected List<CircleRewardTemplate> rewardList;
	protected int[] oldRoleWeights;
	protected int[] newRoleWeights;
	protected List<CircleRankRewardTemplate> rankList;
	protected List<CircleRankRewardTemplate> newServerRankList;
	protected List<CircleShopTemplate> shopList;
	protected CircleActivityConfig config;
	
	public static int CIRCLE_REWARD_COUNT = 12;
	public static final int REQUEST_TYPE_ONE = 0;
	public static final int REQUEST_TYPE_TEN = 1;
	public static int STONE_COST_ONE = 100;
	public static int STONE_COST_TEN = 1000;
	
	private int beginDay;

	public CircleActivity(Activity entity) {
		super(entity);
		App.getApp().getEventManager().register(this);
		TimeUpdater.getInstance().addDayListener(this);
	}

	@Override
	public String getId() {
		return getClass().getName();
	}

	@Override
	public void init() {
		initTemp();
		config = entity.getDataObj(CircleActivityConfig.class);
		beginDay = TimeUtils.ofDay(entity.getBeginTime().getTime());
	}

	@Override
	public void save() {
	}

	@Override
	public void startup() throws ServiceException {
		fireBegin();
	}

	@Override
	public void shutdown() throws ServiceException {
		fireEnd();
	}

	@Override
	public boolean update() {
		return true;
	}

	@Override
	public void setDirty() {
		init();
	}
	
	@Override
	public boolean dayChanged() {
		//排行奖励
		if(isRankingActive()){
			MailService ms = App.getApp().getServiceManager().get(MailService.class);
			List<Ranking> rank = RankingListEnum.CIRCLETODAY.instance.getEntries();
			for(int i = 0; i < rank.size(); i++){
				Ranking rankItem = rank.get(i);
				long pid = rankItem.getPlayerId();
				CircleRankRewardTemplate temp = getRankRewardTempByRank(i + 1);//rank2rewardTemp.get(i + 1);
				int send = 0;
				int tempRank = -1;
				if(temp != null){
					MailAttach attach = new MailAttach();
					if(temp.getMoney() > 0){
						attach.setGold(temp.getMoney());
						send = 1;
					}
					if(temp.getStone() > 0){
						attach.setStone(temp.getStone());
						send = 1;
					}
					int[] itemIds = temp.getItemId();
					int[] itemCounts = temp.getItemCount();
					
					if(itemIds != null && itemCounts != null){
						for(int j = 0; j < itemIds.length; j++){
							attach.addItem(itemIds[j], itemCounts[j]);
							send = 1;
						}
					}
					ms.sendSystemMail(pid, "欢乐轮盘排名奖励", "恭喜您获得了欢乐轮盘排名奖励", attach);
					tempRank = temp.getRank();
				}
				LOG.info("[CIRCLERANKREWARD]ID[{}]RANK[{}]SEND[{}]TEMPRANK[{}]", pid, (i + 1), send, tempRank);
			}
		}
		RankingListEnum.CIRCLETODAY.instance.clearAsync();
		LOG.info("[CIRCLERANKREWARD]CLEARRANK");

		// 重置数据
		if (isActive()) {
			Collection<Player> players = App.getApp().getServiceManager().get(PlayerService.class).getOnlinePlayers();
			for (Player player : players) {
				playerReset(player);
			}
		}
		return true;
	}

	@Override
	public int[] getEventTypes() {
		return new int[] {
				GameEvents.EVENT_PLAYER_LOGIN,
				GameEvents.EVENT_PLAYER_LOADED,
				GameEvents.EVENT_VIP_CHANGED,
		};
	}

	@Override
	public void handleEvent(Event event) {
		switch (event.getType()) {
		case GameEvents.EVENT_PLAYER_LOGIN:
			playerReset(event.getParameter(0));
			break;
		case GameEvents.EVENT_PLAYER_LOADED:
			playerLoaded(event.getParameter(0));
			break;
		case GameEvents.EVENT_VIP_CHANGED:
			playerVipChanged(event.getParameter(0), event.getParameter(1));
			break;
		}
	}

	public void initTemp() {
		rewardList = App.getApp().getServiceManager().get(TemplateService.class).getTemplatesList(CircleRewardTemplate.class);
		int len = rewardList.size();
		if((len % CIRCLE_REWARD_COUNT) > 0){
			throw new IllegalArgumentException("circle.xlsx欢乐转盘奖励数量配置错误");
		}
		this.oldRoleWeights = new int[CIRCLE_REWARD_COUNT];
		this.newRoleWeights = new int[CIRCLE_REWARD_COUNT];
		int totalWeight = 0;
		for(int i = 0; i < CIRCLE_REWARD_COUNT; i++){
			totalWeight = totalWeight + rewardList.get(i).weight;
			oldRoleWeights[i] = totalWeight;
		}
		totalWeight = 0;
		for(int i = 0; i < CIRCLE_REWARD_COUNT; i++){
			totalWeight = totalWeight + rewardList.get(i + CIRCLE_REWARD_COUNT).weight;
			newRoleWeights[i] = totalWeight;
		}
		
		List<CircleRankRewardTemplate> rankRewardList = App.getApp().getServiceManager().get(TemplateService.class).getTemplatesList(CircleRankRewardTemplate.class);
//		rank2rewardTemp = new TIntObjectHashMap<CircleRankRewardTemplate>();
		int lastRank = -1;
		int lastType = 0;
//		rankList = rankRewardList;
		rankList = new ArrayList<CircleRankRewardTemplate>();
		newServerRankList = new ArrayList<CircleRankRewardTemplate>();
		for(int i = 0; i < rankRewardList.size(); i++){
			CircleRankRewardTemplate temp = rankRewardList.get(i);
			if(lastRank < temp.getRank()){
				lastRank = temp.getRank();
			}else{
				if(lastType == temp.getType()){
					throw new IllegalArgumentException("circle.xlsx欢乐转盘排行配置错误->id=" + i + " rank=" + temp.getRank());
				}else{
					lastRank = -1;
					lastType = temp.getType();
				}
			}
			if(temp.getItemId() != null){
				for(int j = 0; j < temp.getItemId().length; j++){
					ItemTemplate itemTemp = App.getApp().getServiceManager().get(TemplateService.class).get(ItemTemplate.class, temp.getItemId()[j]);
					if(itemTemp == null){
						throw new IllegalArgumentException("circle.xlsx欢乐转盘排行奖励配置错误->id=" + i + " itemid=" + temp.getItemId()[j]);
					}
				}
			}
			if(temp.getType() == 0){
				rankList.add(temp);
			}else{
				newServerRankList.add(temp);
			}
//			rank2rewardTemp.put(temp.getRank(), temp);
		}
		
		shopList = App.getApp().getServiceManager().get(TemplateService.class).getTemplatesList(CircleShopTemplate.class);
		for(int i = shopList.size() - 1; i > -1; i--){
			shopList.get(i).setId(i);
		}
	}
	
	public CircleRankRewardTemplate getRankRewardTempByRank(int rank){
		List<CircleRankRewardTemplate> list;
		if(isNewServer()){
			list = newServerRankList;
		}else{
			list = rankList;
		}
		int ret = list.size() - 1;
		int start = 0;
		int end = list.size() - 1;
		while(start <= end){
			int mid = (start + end) >> 1;
			if(list.get(mid).getRank() <= rank){
				start = mid + 1;
				ret = mid;
			}else{
				end = mid - 1;
			}
		}
		return list.get(ret);
	}
	
	public void playerReset(Player player){
		int lastDay = player.getPool().getInt(PlayerPool.PROPERTY_CIRCLE_FREE_COUNT_LAST_RESET_DAY, 0);
		int today = TimeUpdater.getInstance().today();
		if(today != lastDay){
			player.resetCircleFreeCount("LOGIN");
			player.getPool().put(PlayerPool.PROPERTY_CIRCLE_FREE_COUNT_LAST_RESET_DAY, today);
		}
		lastDay = player.getPool().getInt(PlayerPool.PROPERTY_CIRCLE_LAST_ADD_SCORE_DAY, 0);
		if(lastDay < beginDay){
			//TODO
			//如果上次记分时间比本赛季早 重置积分
			player.resetCircleScore("LOGIN");
			player.getPool().put(PlayerPool.PROPERTY_CIRCLE_LAST_ADD_SCORE_DAY, today);
		}
	}
	
	public void playerLoaded(Player player){
		if(isActive()){// && !player.getNewPlayerTasks().checkInActive()
			player.send(new ActivityStatePush(ActivityIds.ACTIVITY_CIRCLE, Activity.STATE_OPENED));
		}
	}
	
	public void playerVipChanged(Player player, int oldLevel){
//		player.resetCircleFreeCount("VIPCHANGE");
		if(oldLevel < 0){
			oldLevel = 0;
		}
		int addval = VipUtils.getTemplate(player.getVipLvl()).getCircleFreeCount() - VipUtils.getTemplate(oldLevel).getCircleFreeCount();
		if(addval > 0){
			player.addCircleFreeCount(addval, "VIPCHANGE");
		}
	}
	
	@PomeloOP(PomeloRoute.ACTIVITY_CIRCLE_INFO)
	public void requestCircleInfo(Session session, ActivityCircleInfoRequest req){
		Player player = session.getClient();
		if(!isActive()){
			player.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_NOT_ACTIVE));
			return;
		}
		List<CircleRewardTemplate> list;
		if(isNewServer()){
			list = rewardList.subList(CIRCLE_REWARD_COUNT, CIRCLE_REWARD_COUNT + CIRCLE_REWARD_COUNT);
		}else{
			list = rewardList.subList(0, CIRCLE_REWARD_COUNT);
		}
		player.send(new ActivityCircleInfoResponse(req.getSerial(), list, player.getCircleScore(), player.getCircleFreeCount(), isRankingActive(), isShopActive(), entity.getEndTime()));
	}
	
	@PomeloOP(PomeloRoute.ACTIVITY_CIRCLE_ROLL)
	public void requestRoll(Session session, ActivityCircleRollRequest req){
		Player player = session.getClient();
		if(!isActive()){
			session.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_NOT_ACTIVE));
			return;
		}
		int type = req.getRollType();
		if(type < 0 || type > 2){
			session.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_TYPE_ERROR));
			return;
		}
		ActivityCircleRollResponse response = new ActivityCircleRollResponse(req.getSerial());
		int ret = tryRoll(player, req.getRollType(), response);
		if(ret == 1){
			session.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_NO_STONE));
			return;
		}else{
			//成功
			response.setCurFreeCount(player.getCircleFreeCount());
			response.setCurScore(player.getCircleScore());
			session.send(response);
		}
	}
	
	/**
	 * roll点
	 * @param player
	 * @param requestType 类型0:1次   1:收费10次
	 * @return 0成功 1资源不足
	 */
	public int tryRoll(Player player, int requestType, ActivityCircleRollResponse response){
		int addScoreOne = 1;//转一次获得的积分
		int forCount = 1;//转几次
		boolean isnew = isNewServer();//checkIsNew(player);
		if(requestType == REQUEST_TYPE_TEN){
			//十次
			if(!player.costStone(STONE_COST_TEN, Cause.CIRCLE_ROLL)){
				return 2;
			}
			addScoreOne = 2;
			forCount = 10;
		}else{
			int currentLeftCount = player.getCircleFreeCount();
			if(currentLeftCount > 0){
				//扣次数
				player.decCircleFreeCount(1, "ROLL");
			}else{
				//扣钻石
				if(!player.costStone(STONE_COST_ONE, Cause.CIRCLE_ROLL)){
					return 2;
				}
				addScoreOne = 2;
			}
		}
		
		int[] resultIndex = new int[forCount];
		int addScore = 0;
		List<CircleRewardInfo> rewardInfoList = new ArrayList<CircleRewardInfo>();
		
		List<CircleRewardTemplate> list;
		if(isnew){
			list = rewardList.subList(CIRCLE_REWARD_COUNT, CIRCLE_REWARD_COUNT + CIRCLE_REWARD_COUNT);
		}else{
			list = rewardList.subList(0, CIRCLE_REWARD_COUNT);
		}
		int[] weights = oldRoleWeights;
		if(isnew){
			weights = newRoleWeights;
		}
		for(int j = 0; j < forCount; j++){
			resultIndex[j] = RandomUtils.getRandomWeightIndex(weights);
			if(resultIndex[j] == -1){
				//日志
				continue;
			}
			CircleRewardTemplate rewardTemp = list.get(resultIndex[j]);
			if(rewardTemp.getType() == 1){
				//钱
				player.addGold(rewardTemp.rewardCount, Cause.CIRCLE_REWARD);
			}else if(rewardTemp.getType() == 2){
				//物品
				player.getBag().addItemWithoutException(rewardTemp.getRewardId(), rewardTemp.getRewardCount(), Cause.CIRCLE_REWARD);
			}
			addScore = addScore + addScoreOne;
			rewardInfoList.add(new CircleRewardInfo(rewardTemp, resultIndex[j]));
		}
		player.addCircleScore(addScore, "ROLL");
		int today = TimeUpdater.getInstance().today();
		player.getPool().put(PlayerPool.PROPERTY_CIRCLE_LAST_ADD_SCORE_DAY, today);
		if(rewardInfoList.size() > 0){
			response.rewardList = rewardInfoList;
		}
		App.getApp().getEventManager().addEvent(GameEvents.EVENT_ADD_CIRCLE_SCORE, player, addScore);
		return 0;
	}
	
	@PomeloOP(PomeloRoute.ACTIVITY_CIRCLE_RANKLIST_INFO)
	public void requestCircleRanklist(Session session, ActivityCircleRankListRequest req){
		Player player = session.getClient();
		if(!isActive()){
			player.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_NOT_ACTIVE));
			return;
		}
		if(!isRankingActive()){
			player.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_NO_RANK));
			return;
		}
		Ranking rank = RankingListEnum.CIRCLETODAY.instance.findEntry(player.getId());
		int index = rank != null? rank.getIndex() + 1 : RankingListEnum.CIRCLETODAY.instance.getCapacity() + CommonUtils.randomInt(10, 100);
		int score = rank != null? (int) rank.getValue() : 0;
		player.send(new ActivityCircleRankListResponse(req.getSerial(), index, score, RankingListEnum.CIRCLETODAY.instance.getEntries(), 0, 20, isNewServer() ? newServerRankList: rankList));
	}
	
	@PomeloOP(PomeloRoute.ACTIVITY_CIRCLE_SHOP_LIST)
	public void requestShopList(Session session, ActivityCircleShopListRequest req){
		Player player = session.getClient();
		if(!isActive()){
			player.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_NOT_ACTIVE));
			return;
		}
		if(!isShopActive()){
			player.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_NO_SHOP));
			return;
		}
		int today = TimeUpdater.getInstance().today();
		int lastDay = player.getPool().getInt(PlayerPool.PROPERTY_CIRCLE_SHOP_LAST_DAY, 0);
		TIntObjectHashMap<Integer> id2count = new TIntObjectHashMap<Integer>();
		if(lastDay == today){
			JSONObject map = player.getPool().getJSONObject(PlayerPool.PROPERTY_CIRCLE_SHOP_BUY_RECORD);
			if(map == null){
				map = new JSONObject();
			}
			for(int i = shopList.size() - 1; i > -1; i--){
				CircleShopTemplate temp = shopList.get(i);
				if(temp.getLimitCount() > 0){
					int count = map.getIntValue(String.valueOf(temp.getId()));
					id2count.put(temp.getId(), count);
				}
			}
		}
		player.send(new ActivityCircleShopListResponse(req.getSerial(), shopList, player.getCircleScore(), id2count, isNewServer()));
	}
	
	@PomeloOP(PomeloRoute.ACTIVITY_CIRCLE_SHOP_BUY)
	public void requestBuy(Session session, ActivityCircleShopBuyRequest req){
		Player player = session.getClient();
		if(!isActive()){
			player.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_NOT_ACTIVE));
			return;
		}
		if(!isShopActive()){
			player.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_NO_SHOP));
			return;
		}
		int index = req.getBuyIndex();
		if(index < 0 || index >= shopList.size()){
			player.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_NO_ITEM));
			return;
		}
		CircleShopTemplate shopItemTemp = shopList.get(index);
		if(shopItemTemp == null){
			player.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_NO_ITEM));
			return;
		}
		ItemTemplate itemTemp = null;
		if(shopItemTemp.getType() == 2){
			TemplateService ts = App.getApp().getServiceManager().get(TemplateService.class);
			itemTemp = ts.get(ItemTemplate.class, shopItemTemp.itemId);
			if(itemTemp == null){
				player.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_NO_ITEM));
				return;
			}
		}
		//次数
		int today = TimeUpdater.getInstance().today();
		int lastDay = player.getPool().getInt(PlayerPool.PROPERTY_CIRCLE_SHOP_LAST_DAY, 0);
		JSONObject map;
		map = player.getPool().getJSONObject(PlayerPool.PROPERTY_CIRCLE_SHOP_BUY_RECORD);
		if(today != lastDay || map == null){
			map = new JSONObject();
			player.poolSet(PlayerPool.PROPERTY_CIRCLE_SHOP_LAST_DAY, today);
			player.poolSet(PlayerPool.PROPERTY_CIRCLE_SHOP_BUY_RECORD, map);
		}
		int count = 0;
		if(shopItemTemp.getLimitCount() > 0){
			count = map.getIntValue(String.valueOf(shopItemTemp.getId()));
			if(shopItemTemp.getLimitCount() - count <= 0){
				player.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_SHOP_NO_COUNT));
				return;
			}
		}
		
//		if(shopItemTemp.getPrice() != req.getReqPrice()){
//			player.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_CIRCLE_ERROR));
//			return;
//		}
		//扣积分
		boolean succ = player.decCircleScore(shopItemTemp.price, "BUY");
		if(!succ){
			player.send(new HintResponse(req.getSerial(), MessageConst.SCORE_NOT_ENOUGH));
			return;
		}
		//加物品
		String itemName = null;
		switch (shopItemTemp.getType()) {
		case 1://钱
			itemName = "现金";
			player.addGold(shopItemTemp.itemCount, Cause.CIRCLE_BUY);
			break;
		case 2://物品
			itemName = itemTemp.getName();
			player.getBag().addItemOrSendMail(shopItemTemp.itemId, shopItemTemp.itemCount, Cause.CIRCLE_BUY);
			break;
		}
		//扣次数
		int leftCount = -1;
		if(shopItemTemp.getLimitCount() > 0){
			count++;
			map.put(String.valueOf(shopItemTemp.getId()), count);
			player.poolSet(PlayerPool.PROPERTY_CIRCLE_SHOP_BUY_RECORD, map);
			leftCount = shopItemTemp.getLimitCount() - count;
		}
		
		player.send(new ActivityCircleShopBuyResponse(req.getSerial(), index, itemName, shopItemTemp.itemCount, shopItemTemp.price, player.getCircleScore(), leftCount));
	}
	
	public boolean isNewServer() {
		long now = TimeUpdater.getInstance().now();
		return now >= config.serverNewBeginTime && now <= config.serverNewEndTime;
	}
	
	public boolean isRankingActive() {
		long now = TimeUpdater.getInstance().now();
		return now >= config.rankingOpenTime && now <= config.rankingCloseTime;
	}
	
	public boolean isShopActive() {
		long now = TimeUpdater.getInstance().now();
		return now >= config.shopOpenTime && now <= config.shopCloseTime;
	}
	
	public void fireBegin() {
		Server.broadcast(new ActivityStatePush(ActivityIds.ACTIVITY_CIRCLE, Activity.STATE_OPENED));
		// 重置数据
		Collection<Player> players = App.getApp().getServiceManager().get(PlayerService.class).getOnlinePlayers();
		for (Player player : players) {
			playerReset(player);
		}
	}
	
	public void fireEnd() {
		Server.broadcast(new ActivityStatePush(ActivityIds.ACTIVITY_CIRCLE, Activity.STATE_CLOSED));
	}

}
